import store from '@/store'
import config from '@/config'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { toast, showConfirm, tansParams } from '@/utils/common'

let timeout = 15000
const baseUrl = config.baseUrl
const httpList = {}
const request = config => {
  // 是否需要设置 token
  const isToken = (config.header || {}).isToken === false
  config.header = config.header || {}
  if (getToken() && !isToken) {
    config.header['Authorization'] = 'Bearer ' + getToken()
  }
  const curHospitalId = store.getters.curHospitalId
  if (curHospitalId) {
    config.header['Hospital-Id'] = curHospitalId
  }
  let apiUrl = config.url
  // get请求映射params参数
  if (config.params) {
    let url = config.url + '?' + tansParams(config.params)
    url = url.slice(0, -1)
    config.url = url
  }
  if(httpList[apiUrl] && config.isCancel){
    // abort中断请求
    httpList[apiUrl].abort()
    delete httpList[apiUrl]
  }
  config = RefreshOps.configMarkId(config)
  return new Promise((resolve, reject) => {
    RefreshOps.request(RefreshOps.configMarkId(config)).then(() => {
      httpList[apiUrl] = uni.request({
        method: config.method || 'get',
        timeout: config.timeout || timeout,
        url: config.baseUrl || baseUrl + config.url,
        data: config.data,
        header: config.header,
        dataType: 'json',
        success: response => {
          const code = response.data.code || 200
          const msg = errorCode[code] || response.data.msg || errorCode['default']
          if(config.preventResponseInterceptor){
            return RefreshOps.responseResolve({...response, config}).then(() => {
              resolve(response.data)
              return Promise.resolve(response.data)
            })
          }
          if (code === 401) {
            if (config.url.startsWith('/login') && config.params.grantType === 'refresh') {
              return RefreshOps.responseReject({...response, config}).catch(() => {
                reject('无效的会话，或者会话已过期，请重新登录。')
                return Promise.reject('无效的会话，或者会话已过期，请重新登录。')
              })
            }
            return RefreshOps.resend({...response, config}).then(res => {
              resolve(res)
              return Promise.resolve(res)
            }).catch(err => {
              reject(err)
              return Promise.reject(err)
            })
          } else if (code === 500) {
            toast(msg)
            return RefreshOps.responseReject({...response, config}).catch(() => {
              reject('500')
              return Promise.reject('500')
            })
          } else if (code !== 200) {
            toast(msg)
            return RefreshOps.responseReject({...response, config}).catch(() => {
              reject(code)
              return Promise.reject(code)
            })
          }
          return RefreshOps.responseResolve({...response, config}).then(() => {
            resolve(response.data)
            return Promise.resolve(response.data)
          })
        },
        fail: error => {
          if(config.preventResponseInterceptor){
            return RefreshOps.responseReject({...error, config}).catch(() => {
              reject(error)
            })
          }
          let { errMsg } = error
          if (errMsg.includes('timeout')) {
            errMsg = '系统接口请求超时'
          } else if (errMsg.includes('Request failed with status code')) {
            errMsg = '系统接口' + errMsg.substr(errMsg.length - 3) + '异常'
          } else if (errMsg.includes('fail abort')){
            RefreshOps.responseReject({...error, config}).catch(() => {
              reject(error)
            })
            return
          } else if (errMsg === 'Network Error' || errMsg === 'request:fail')  {
            errMsg = '后端接口连接异常'
          }
          toast(errMsg)
          RefreshOps.responseReject({...error, config}).catch(() => {
            reject(error)
          })
        }
      })
    }).catch(err => {
      const {message} = err
      if (message) {
        toast(message)
      }
      reject(err)
    })
  })
}

class RefreshOps {
  static REFRESH_STATUS = {
    NORMAL: 'normal',
    PROCESSING: 'processing',
    FAILED: 'failed'
  }
  static status = RefreshOps.REFRESH_STATUS.NORMAL
  static refreshPr = Promise.resolve()
  static idKey = 'randomId'
  static pendingRequestConfigList = []
  static resendRequestConfigList = []
  // public
  static configMarkId(config, idKey = RefreshOps.idKey) {
    if (config[idKey]) return config
    else return {
      ...config,
      [idKey]: `${Math.random()}`
    }
  }
  // public
  static request(config) {
    RefreshOps.addPending(config)
    if ((config.header || {}).isToken !== false
      && RefreshOps.status === RefreshOps.REFRESH_STATUS.PROCESSING
      && (!config.url.startsWith('/login') || config.params.grantType !== 'refresh')
    ) {
      return new Promise((resolve, reject) => {
        RefreshOps.refreshPr.then(() => {
          config.header['Authorization'] = 'Bearer ' + getToken()
          resolve(config)
        }).catch(err => {
          RefreshOps.removePending(config[RefreshOps.idKey])
          reject(err)
        })
      })
    } else if ((config.header || {}).isToken !== false
      && RefreshOps.status === RefreshOps.REFRESH_STATUS.FAILED
      && (!config.url.startsWith('/login') && !config.url.startsWith('/logout'))
    ) {
      RefreshOps.removePending(config[RefreshOps.idKey])
      return Promise.reject({config, message: `无效的会话，或者会话已过期，请重新登录。`})
    } else if (config.url.startsWith('/login')) {
      RefreshOps.status = RefreshOps.REFRESH_STATUS.NORMAL
      return Promise.resolve(config)
    }
    return Promise.resolve(config)
  }
  // public
  static resend(response) {
    const {config} = response
    config.url = config.url.split('?')[0]
    const isExistResend = RefreshOps.existInResend(config[RefreshOps.idKey])
    if (!isExistResend) {
      RefreshOps.initResend()
      return new Promise((resolve, reject) => {
        RefreshOps.doRefresh().then(() => {
          request(config)
            .then(res => resolve(res))
            .catch(err => reject(err))
            .finally(() => RefreshOps.removeResend(config[RefreshOps.idKey]))
        }).catch(err => reject(err))
      })
    }
    if (RefreshOps.status !== RefreshOps.REFRESH_STATUS.FAILED) {
      return new Promise((resolve, reject) => {
        RefreshOps.refreshPr.then(() => {
          request(config)
            .then(res => resolve(res))
            .catch(err => reject(err))
            .finally(() => RefreshOps.removeResend(config[RefreshOps.idKey]))
        }).catch(err => reject(err))
      })
    }
    RefreshOps.removeResend(config[RefreshOps.idKey])
    return RefreshOps.responseReject(response)
  }
  // public
  static responseResolve(response) {
    RefreshOps.removePending(response.config[RefreshOps.idKey])
    return Promise.resolve(response.data)
  }
  // public
  static responseReject(response, errorMsg) {
    RefreshOps.removePending(response.config[RefreshOps.idKey])
    return Promise.reject(errorMsg || response)
  }
  // private
  static doRefresh() {
    if (RefreshOps.status === RefreshOps.REFRESH_STATUS.NORMAL) {
      RefreshOps.refreshPr = new Promise((resolve, reject) => {
        RefreshOps.status = RefreshOps.REFRESH_STATUS.PROCESSING
        store.dispatch('RefreshToken')
          .then(() => {
            RefreshOps.status = RefreshOps.REFRESH_STATUS.NORMAL
            resolve()
          })
          .catch(err => {
            showConfirm('登录状态已过期，您可以继续留在该页面，或者重新登录?').then(res => {
              if (res.confirm) {
                //没有token直接跳转到登录页
                if(!getToken()){
                  uni.reLaunch({ url: '/pages/login' })
                }
                //有token则需做登出操作
                else{
                  store.dispatch('LogOut').then(res => {
                    uni.reLaunch({ url: '/pages/login' })
                  })
                }
              }
            })
            RefreshOps.status = RefreshOps.REFRESH_STATUS.FAILED
            reject(err)
          })
      })
    }
    return RefreshOps.refreshPr
  }
  // private
  static removePending(id, idKey = RefreshOps.idKey) {
    RefreshOps.pendingRequestConfigList = RefreshOps.pendingRequestConfigList.filter(config => config[idKey] !== id)
  }
  // private
  static removeResend(id, idKey = RefreshOps.idKey) {
    RefreshOps.resendRequestConfigList = RefreshOps.resendRequestConfigList.filter(config => config[idKey] !== id)
  }
  // private
  static existInPending(id, idKey = RefreshOps.idKey) {
    return RefreshOps.pendingRequestConfigList.some(pendingConfig => pendingConfig[idKey] === id)
  }
  // private
  static existInResend(id, idKey = RefreshOps.idKey) {
    return RefreshOps.resendRequestConfigList.some(resendConfig => resendConfig[idKey] === id)
  }
  // private
  static addPending(config, idKey = RefreshOps.idKey) {
    const isExistPending = RefreshOps.existInPending(config[RefreshOps.idKey])
    if (!isExistPending) {
      RefreshOps.pendingRequestConfigList.push(config)
    }
  }
  // private
  static initResend() {
    RefreshOps.resendRequestConfigList = [...RefreshOps.pendingRequestConfigList]
  }

}

export default request
